package cn.mw.cmdb.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.mw.cmdb.config.CustomizeThreadPool;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.enums.BatchScanStatusEnum;
import cn.mw.cmdb.enums.ProxyTypeEnum;
import cn.mw.cmdb.exception.AssetsDiscoverException;
import cn.mw.cmdb.exception.CompoundException;
import cn.mw.cmdb.exception.DataUniqueException;
import cn.mw.cmdb.exception.FindNoException;
import cn.mw.cmdb.mongoMapper.AssetsDiscoverMapper;
import cn.mw.cmdb.mongoMapper.AssetsScanResultMapper;
import cn.mw.cmdb.param.*;
import cn.mw.cmdb.service.ServiceAction;
import cn.mw.cmdb.task.AssetScanServiceContext;
import cn.mw.cmdb.task.AssetsDiscoveryMainTask;
import cn.mw.cmdb.task.AssetsDiscoveryRunManage;
import cn.mw.cmdb.timeplan.service.impl.MwTimePlanCommonImpl;
import cn.mw.cmdb.util.CMDBCommonUtil;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.components.mongodb.exception.BusinessException;
import cn.mw.components.mongodb.mapper.BaseMapper;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.microMonitorCommon.api.common.Constants;
import cn.mw.microMonitorCommon.api.common.MwTPServerService;
import cn.mw.microMonitorCommon.api.scan.IPRangeParam;
import cn.mw.microMonitorCommon.api.scan.RuleParam;
import cn.mw.microMonitorCommon.api.scan.SubnetParam;
import cn.mw.microMonitorCommon.api.user.MwUserApi;
import cn.mw.microMonitorCommon.entity.common.MwTPServerTable;
import cn.mw.microMonitorCommon.enums.MwTimePlanEnum;
import cn.mw.microMonitorCommon.enums.ServerTypeEnum;
import cn.mw.microMonitorCommon.param.MwTimePlanparam;
import cn.mw.microMonitorCommon.security.dto.MwUser;
import cn.mw.microMonitorCommon.util.ModuleIDManager;
import cn.mw.microMonitorCommon.util.RedisUtils;
import cn.mw.microMonitorCommon.util.SpringUtils;
import com.alibaba.fastjson2.JSON;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.mw.cmdb.param.MwScanTypeDiscoveryEnum.autoScan;
import static cn.mw.cmdb.param.MwScanTypeDiscoveryEnum.manualScan;
import static cn.mw.cmdb.util.CMDBTool.getFieldName;
import static cn.mw.cmdb.view.ViewConvert.ascSortModel;

@Slf4j
public class AssetsDiscoverServiceImpl extends ModelBaseServiceImpl<AssetsDiscoverInfo, Object> {

    public static final String ID = "assetsDiscover";
    public static final String TASK_RULE_ID_KEY = "taskRuleId";

    protected static final Map<String, Integer> MONGO_SAVE_PROGRESS = new ConcurrentHashMap<>();

    private final CmdbServiceManage cmdbServiceManage;

    private final AssetsDiscoverMapper assetsDiscoverMapper;

    private RedisUtils redisUtils;

    private final ModuleIDManager moduleIDManager;
    private final MwUserApi userApi;

    private AssetsScanResultMapper detailMapper;

    private AssetsDiscoveryRunManage runManage;

    private MwTPServerService mwTPServerService;

    private AssetsScanResultMapper assetsScanResultMapper;

    public AssetsDiscoverServiceImpl(CmdbServiceManage cmdbServiceManage, AssetsDiscoverMapper assetsDiscoverMapper
            , ModuleIDManager moduleIDManager, MwUserApi mwUserApi, RedisUtils redisUtils, AssetsScanResultMapper detailMapper
            , AssetsDiscoveryRunManage runManage, MwTPServerService mwTPServerService, AssetsScanResultMapper assetsScanResultMapper) {
        this.cmdbServiceManage = cmdbServiceManage;
        this.assetsDiscoverMapper = assetsDiscoverMapper;
        this.moduleIDManager = moduleIDManager;
        this.userApi = mwUserApi;
        this.redisUtils = redisUtils;
        this.detailMapper = detailMapper;
        this.runManage = runManage;
        this.mwTPServerService = mwTPServerService;
        this.assetsScanResultMapper = assetsScanResultMapper;
    }

    @Override
    public AssetsDiscoverInfo genObject() {
        return new AssetsDiscoverInfo();
    }

    @Override
    Object doAdd(AssetsDiscoverInfo param) throws Exception {
        if (param.getExecutorNow() != null && Boolean.TRUE.equals(param.getExecutorNow())) {
            param.setStatus(BatchScanStatusEnum.scanning.name());
        } else {
            param.setStatus(BatchScanStatusEnum.not_start.name());
        }
        param.initRuleParam();
        Query query = new Query(CriteriaWrapper.where(AssetsDiscoverInfo::getRuleName).is(param.getRuleName()));
        long count = assetsDiscoverMapper.count(query);
        if (count > 0) {
            CompoundException instanceParamValidateException = new CompoundException();
            instanceParamValidateException.addInstanceValidateException(new DataUniqueException(new Object[]{param.getRuleName()}));
            throw instanceParamValidateException;
        }
        // 添加之前做业务逻辑的判断
        assetsDiscoverMapper.insert(param);
        //根据扫描方式判断是否是定时任务执行
        if (autoScan.name().equals(param.getScanType())) {
            createTimeTaskScanPlan(param);
        }
        return true;
    }

    @Override
    boolean doUpdate(AssetsDiscoverInfo param) throws Exception {
        param.initRuleParam();
        Query query = new Query(CriteriaWrapper.where(AssetsDiscoverInfo::getRuleName).is(param.getRuleName()));

        AssetsDiscoverInfo info = assetsDiscoverMapper.findOne(query);
        if (ObjectUtils.isNotEmpty(info) && !info.getId().equals(param.getId())) {
            CompoundException instanceParamValidateException = new CompoundException();
            instanceParamValidateException.addInstanceValidateException(new DataUniqueException(new Object[]{param.getRuleName()}));
            throw instanceParamValidateException;
        }


        if (param.getScanType() != null) {
            String nowScanType = param.getScanType().name();
            if (autoScan.name().equals(nowScanType)) {
                //自动，创建定时执行任务
                createTimeTaskScanPlan(param);
            }
            if (manualScan.name().equals(nowScanType)) {
                //手动，关闭定时任务
                deleteTimePlanRelationInfo(param);
            }
        }
        updateAssetsDiscoverInfoById(param);
        return true;
    }

    private void updateAssetsDiscoverInfoById(AssetsDiscoverInfo param) throws Exception {
        Query query = new Query(CriteriaWrapper.where(AssetsDiscoverInfo::getId).is(param.getId()));
        Update update = CMDBTool.genMongoUpdate(param, null, null);
        CMDBTool.updateFirst(assetsDiscoverMapper, query, update);
    }

    @Override
    boolean doRemove(AssetsDiscoverInfo param) throws Exception {
        return false;
    }

    @Override
    Object doBatchAdd(Object params) throws Exception {
        return false;
    }

    @Override
    boolean doBatchUpdate(Object params) throws Exception {
        List<AssetsDiscoverInfo> infoList = (List<AssetsDiscoverInfo>) params;
        if (CollectionUtil.isEmpty(infoList)) {
            throw new BusinessException("not-data");
        }
        for (AssetsDiscoverInfo discoverInfo : infoList) {
            doUpdate(discoverInfo);
        }
        return true;
    }

    @Override
    AssetsDiscoverInfo doSelectById(Object id) throws Exception {
        return assetsDiscoverMapper.findById(id);
    }

    public List<AssetsDiscoverInfo> doSelectByIds(Collection<String> ids) throws Exception {
        Query query = new Query();
        Criteria criteria = CriteriaWrapper.where(AssetsDiscoverInfo::getId).in(ids);
        query.addCriteria(criteria);
        return assetsDiscoverMapper.find(query);
    }

    public List<String> getRuleNamesByIds(Collection<String> ids) throws Exception {
        List<AssetsDiscoverInfo> infoList = doSelectByIds(ids);
        infoList = Optional.ofNullable(infoList).orElse(new ArrayList<>());
        return infoList.stream().map(AssetsDiscoverInfo::getRuleName).toList();
    }

    @Override
    List<AssetsDiscoverInfo> doSelectList(Object param) throws Exception {
        AssetsDiscoverSearchParam searchParam = (AssetsDiscoverSearchParam) param;
        Criteria criteria = genCriteria(searchParam);
        searchParam.setPage(null);
        return CMDBTool.selectPageList(assetsDiscoverMapper, criteria, searchParam);
    }

    @Override
    boolean doBatchRemove(Object params) throws Exception {
        AssetsDiscoverIdsParam param = (AssetsDiscoverIdsParam) params;
        Query query = new Query(CriteriaWrapper.where(AssetsDiscoverInfo::getId).in(param.getIds()));
        assetsDiscoverMapper.remove(query);
        return true;
    }

    public List<AssetsDiscoverInfoVo> discoverInfoConvertDiscoverInfoVo(List<AssetsDiscoverInfo> list, AssetsDiscoverSearchParam param) throws Exception {

        //获取扫描记录中最大批次的最新扫描数据，统计扫描资产数量
        AssetsScanResultServiceImpl assetsScanResultService = (AssetsScanResultServiceImpl) cmdbServiceManage.getModelService(AssetsScanResultServiceImpl.ID);
        List<AssetsScanTotalResultInfo> scanTotalResultInfos = assetsScanResultService.getScanTotalResultInfos(null);
        Map<String, AssetsScanResultCountParam> mapResult = new HashMap<>();
        for (AssetsScanTotalResultInfo scanResultInfo : scanTotalResultInfos) {
            AssetsScanResultCountParam countParam = new AssetsScanResultCountParam();
            countParam.setFailNum(scanResultInfo.getFailList() != null ? scanResultInfo.getFailList().size() : 0);
            countParam.setSuccessNum(scanResultInfo.getSuccessList() != null ? scanResultInfo.getSuccessList().size() : 0);
            countParam.setTotalNum(countParam.getFailNum() + countParam.getSuccessNum());
            mapResult.put(scanResultInfo.getId(), countParam);
        }
        //查找正在扫描的信息
        Map<String, AssetsDiscoverInfo> scanningMap = runManage.getScaningAssetsDiscoverInfoMap();
        for (AssetsDiscoverInfo assetsDiscoverInfo : list) {
            AssetsDiscoverInfo scanning = scanningMap.get(assetsDiscoverInfo.getId());
            if (null != scanning) {
                assetsDiscoverInfo.setStatus(BatchScanStatusEnum.scanning.name());
            }
        }

        List<AssetsDiscoverInfoVo> assetsDiscoverInfoVos = BeanUtil.copyToList(list, AssetsDiscoverInfoVo.class);
        List<Long> userIds = assetsDiscoverInfoVos.stream().map(AssetsDiscoverInfoVo::getExecutor).filter(StrUtil::isNotBlank).map(Long::parseLong).toList();
        Map<String, String> userIdMap = null;
        if (CollectionUtil.isNotEmpty(userIds)) {
            List<MwUser> usersByUserIds = userApi.getUsersByUserIds(userIds);
            if (CollectionUtil.isNotEmpty(usersByUserIds)) {
                userIdMap = usersByUserIds.stream().collect(Collectors.toMap(k -> String.valueOf(k.getId()), MwUser::getNickName, (o1, o2) -> o1));
            }
        }
        for (AssetsDiscoverInfoVo item : assetsDiscoverInfoVos) {
            if (userIdMap != null && userIdMap.containsKey(item.getExecutor())) {
                item.setExecutor(userIdMap.get(item.getExecutor()));
            }
            if (item.getScanStartDate() != null && item.getScanEndDate() != null) {
                item.setTimeLength(scanRuleTime(item.getScanStartDate(), item.getScanEndDate()));
            }
            if (mapResult != null && mapResult.containsKey(item.getId())) {
                AssetsScanResultCountParam countParam = mapResult.get(item.getId());
                item.setTotalNum(countParam.getTotalNum());
                item.setSuccessNum(countParam.getSuccessNum());
                item.setFailNum(countParam.getFailNum());
            }
        }
        //默认按id倒序
        if (CollectionUtil.isNotEmpty(assetsDiscoverInfoVos) && Strings.isNullOrEmpty(param.getSortName())) {
            assetsDiscoverInfoVos = assetsDiscoverInfoVos.stream().sorted(Comparator.comparing(AssetsDiscoverInfoVo::getId).reversed()).toList();
        }

        if (CollectionUtil.isNotEmpty(assetsDiscoverInfoVos) && !Strings.isNullOrEmpty(param.getSortName()) && getFieldName(AssetsDiscoverInfoVo::getTimeLength).equals(param.getSortName())) {
            boolean isAsc = ascSortModel.equals(param.getSortOrder());
            if (isAsc) {
                assetsDiscoverInfoVos = assetsDiscoverInfoVos.stream().sorted(Comparator.comparing(AssetsDiscoverInfoVo::getTimeLength)).toList();
            } else {
                //降序
                assetsDiscoverInfoVos = assetsDiscoverInfoVos.stream().sorted(Comparator.comparing(AssetsDiscoverInfoVo::getTimeLength).reversed()).toList();
            }
        }

        return assetsDiscoverInfoVos;
    }

    public Object batchAdd(ModelAddTangAssetsParam param) throws Exception {
        List<String> scanSuccessIdList = param.getScanAssetsIds();
        boolean isAllinAdd = CollectionUtil.isEmpty(scanSuccessIdList);
        String scanRuleId = param.getId();
        // 根据taskId获取资产信息
        AssetsScanResultServiceImpl assetsScanResultService = (AssetsScanResultServiceImpl) cmdbServiceManage.getModelService(AssetsScanResultServiceImpl.ID);
        List<AssetsScanTotalResultInfo> scanTotalResultInfos = assetsScanResultService.getScanTotalResultInfos(scanRuleId);
        if (ObjUtil.isEmpty(scanTotalResultInfos)) {
            throw new BusinessException("instance-not-found");
        }
        if(CollectionUtil.isNotEmpty(scanTotalResultInfos)){
            List<ScanResultSuccessInfo> successAllResultList = new ArrayList<>();
            for(AssetsScanTotalResultInfo totalResultInfo : scanTotalResultInfos){
                List<ScanResultSuccessInfo> successResultList = totalResultInfo.getSuccessList();
                if (!isAllinAdd) {
                    // 过滤出successResultList集合中匹配scanSuccessIdList的集合
                    successAllResultList.addAll(successResultList.stream().filter(e -> scanSuccessIdList.contains(e.getId())).toList());
                }
            }
            List<InstanceInfo> instanceInfos = assetsScanResultService.instanceConvert(successAllResultList, param);
            BatchAddAndUpdInstanceParam batchAddAndUpdInstanceParam = new BatchAddAndUpdInstanceParam();
            batchAddAndUpdInstanceParam.setParams(instanceInfos);
            cmdbServiceManage.service(batchAddAndUpdInstanceParam, ServiceAction.batchAdd);
            // 只有批量添加
            if (Boolean.FALSE.equals(param.getBatchManage())) {
                assetsScanResultService.doBatchUpdateByRuleIdAndIp(scanRuleId, successAllResultList.stream().map(ScanResultSuccessInfo::getIpAddress).toList());
            }
        }
        return true;
    }


//    public Object batchAdd(ModelAddTangAssetsParam param) throws Exception {
//        List<String> scanSuccessIpList = param.getScanSuccessIpList();
//        boolean isAllinAdd = CollectionUtil.isEmpty(scanSuccessIpList);
//        String id = param.getId();
//        // 根据id获取资产发现信息
//        AssetsDiscoverInfo discoverInfo = doSelectById(id);
//        if (ObjUtil.isEmpty(discoverInfo)) {
//            throw new BusinessException("instance-not-found");
//        }
//
//        // 根据taskId获取资产信息
//        AssetsScanResultServiceImpl assetsScanResultService = (AssetsScanResultServiceImpl) cmdbServiceManage.getModelService(AssetsScanResultServiceImpl.ID);
//        AssetsInstanceScanSearchParam assetsScanResultInfoParam = new AssetsInstanceScanSearchParam();
//        assetsScanResultInfoParam.setId(id);
//        assetsScanResultInfoParam.setBatchNo(discoverInfo.getMaxBatchNo());
//        AssetsScanResultInfo assetsScanResultInfo = assetsScanResultService.doSelectById(assetsScanResultInfoParam);
//        List<ScanResultSuccessInfo> successResultList = assetsScanResultInfo.getSuccessList();
//        if (!isAllinAdd) {
//            // 过滤出successResultList集合中匹配scanSuccessIdList的集合
//            successResultList = successResultList.stream().filter(e -> scanSuccessIpList.contains(e.getIpAddress())).toList();
//        }
//        List<InstanceInfo> instanceInfos = assetsScanResultService.instanceConvert(successResultList, param);
//
//        BatchAddAndUpdInstanceParam batchAddAndUpdInstanceParam = new BatchAddAndUpdInstanceParam();
//        batchAddAndUpdInstanceParam.setParams(instanceInfos);
//        cmdbServiceManage.service(batchAddAndUpdInstanceParam, ServiceAction.batchAdd);
//
//        // 只有批量添加
//        if (Boolean.FALSE.equals(param.getBatchManage())) {
//            assetsScanResultService.doBatchUpdateByRuleIdAndIp(id, successResultList.stream().map(ScanResultSuccessInfo::getIpAddress).toList());
//        }
//        return true;
//    }

    /**
     * 立即执行
     * String executorNow = strValueConvert(dataContext.getDataBefore().get(CMDBTool.getFieldName(AssertBatchScanProperty::getMw_executorNow)));
     * // 选择的立即执行
     * if (StringUtils.hasText(executorNow) && Boolean.TRUE.equals(Boolean.valueOf(executorNow))) {
     * ExecutorService executorService = Executors.newFixedThreadPool(1);
     * executorService.execute(() -> {
     * InstanceRuleExecutorParam executorParam = new InstanceRuleExecutorParam();
     * executorParam.setIds(Collections.singletonList(param.getId()));
     * try {
     * executorNow(executorParam);
     * } catch (Exception ignored) {
     * }
     * });
     * }
     *
     * @param param 执行参数
     * @return 执行结果
     */
    public Object executorNow(InstanceRuleExecutorParam param) throws Exception {
        List<String> ids = param.getIds();
        discoverScan(ids);
        return getAssetDiscoverInfoListByIds(ids);
    }

    public void failAssetsScan(AssetsScanFailParam param) throws Exception {
        String id = param.getId();
        if (runManage.hasTask(id)) {
            AssetsDiscoverException e = new AssetsDiscoverException("assets-scan-exist");
            e.setArgs(new String[]{id});
            throw e;
        }
        AssetsDiscoverInfo discoverInfo = doSelectById(id);
        List<String> failScanIds = param.getFailScanIps();
        //获取是否为全部失败扫描
        boolean isAllinScan = CollectionUtils.isEmpty(failScanIds);

        // 获取资产对象
        AssetsScanResultServiceImpl assetsScanResultService = (AssetsScanResultServiceImpl) this.cmdbServiceManage.getModelService(AssetsScanResultServiceImpl.ID);
        AssetsInstanceScanSearchParam scanResultInfoParam = new AssetsInstanceScanSearchParam();
        scanResultInfoParam.setId(id);
        scanResultInfoParam.setBatchNo(discoverInfo.getMaxBatchNo());
        // 获取任务ID对象的扫描的信息
        AssetsScanResultInfo assetsScanResultInfo = assetsScanResultService.doSelectById(scanResultInfoParam);
        if (ObjUtil.isEmpty(assetsScanResultInfo) || CollectionUtils.isEmpty(assetsScanResultInfo.getFailList())) {
            throw new FindNoException("find-no-scan-task");
        }

        // 获取失败的ID，如果表示为空则扫描所以失败IP
        List<ScanResultFailInfo> failResultList = assetsScanResultInfo.getFailList();
        if (!isAllinScan) {
            failResultList = failResultList.stream().filter(e -> failScanIds.contains(e.getIpAddress())).toList();
        }
        if (CollectionUtils.isEmpty(failResultList)) {
            throw new FindNoException("find-no-scan-task");
        }

        // 资产扫描执行
        AssetsScanParam scanParam = failResultListConvertScanParam(failResultList, id);

        Map<String, AssetsDiscoverInfo> assetsDiscoverInfoMap = new HashMap<>();
        assetsDiscoverInfoMap.put(discoverInfo.getId(), discoverInfo);

        ThreadPoolTaskExecutor executor = SpringUtils.getBean(CustomizeThreadPool.ScanThreadPool, ThreadPoolTaskExecutor.class);
        log.info("executor info ActiveCount:{},PoolSize:{},MaxPoolSize:{},queueSize:{}"
                , executor.getActiveCount(), executor.getPoolSize(), executor.getMaxPoolSize(), executor.getQueueSize());
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        RedisUtils redisUtil = SpringUtils.getBean(RedisUtils.class);
        executor.submit(new AssetsDiscoveryMainTask(authentication, detailMapper, assetsDiscoverMapper
                , Collections.singletonList(scanParam), assetsDiscoverInfoMap, runManage, redisUtil, false, cmdbServiceManage));

    }

    /**
     * 资产发现停止扫描
     *
     * @throws Exception 内部异常
     */
    public void stopScan(List<String> ids) throws Exception {
        for (String id : ids) {
            AssetScanServiceContext task = runManage.getTask(id);
            if (null != task) {
                task.stopService();
                runManage.removeTask(id);
                AssetsDiscoverInfo assetsDiscoverInfo = new AssetsDiscoverInfo();
                assetsDiscoverInfo.setId(id);
                runManage.clearDiscovery(assetsDiscoverInfo);
            }
        }
    }

    /**
     * 资产发现扫描接口
     *
     * @throws Exception 内部异常
     */
    public void discoverScan(List<String> ids) throws Exception {
        //检查是否存在正在扫描的规则
        for (String id : ids) {
            if (runManage.hasTask(id)) {
                AssetsDiscoverException e = new AssetsDiscoverException("assets-scan-exist");
                e.setArgs(new String[]{id});
                throw e;
            }
        }

        //获取资产发现配置信息
        List<AssetsDiscoverInfo> discoverInfos = getAssetDiscoverInfoListByIds(ids);

        // 状态过滤 执行中的不能执行
        List<AssetsDiscoverInfo> discoverInfoList = filterExecutorDiscoverInfo(discoverInfos);

        // 实例对象转为资产扫描对象
        log.info("The asset scan starts..");
        log.info("instance obj to asset scan obj ..");
        List<AssetsScanParam> scanParamList = instanceToScanParam(discoverInfoList);
        Map<String, AssetsDiscoverInfo> assetsDiscoverInfoMap = discoverInfoList.stream().collect(Collectors.toMap(AssetsDiscoverInfo::getId, Function.identity()));

        // 资产扫描执行
        log.info("start scan..");
        ids.forEach(MONGO_SAVE_PROGRESS::remove);
        ThreadPoolTaskExecutor executor = SpringUtils.getBean(CustomizeThreadPool.ScanThreadPool, ThreadPoolTaskExecutor.class);
        log.info("executor info ActiveCount:{},PoolSize:{},MaxPoolSize:{},queueSize:{}"
                , executor.getActiveCount(), executor.getPoolSize(), executor.getMaxPoolSize(), executor.getQueueSize());
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        RedisUtils redisUtil = SpringUtils.getBean(RedisUtils.class);
        executor.submit(new AssetsDiscoveryMainTask(authentication, detailMapper, assetsDiscoverMapper
                , scanParamList, assetsDiscoverInfoMap, runManage, redisUtil, true, cmdbServiceManage));
    }

    /**
     * 过滤不能被扫描的数据 - 扫描中的规则
     *
     * @param discoverInfos 资产发现的数据
     * @return 可被扫描的规则
     */
    private List<AssetsDiscoverInfo> filterExecutorDiscoverInfo(List<AssetsDiscoverInfo> discoverInfos) {
        List<AssetsDiscoverInfo> list = discoverInfos.stream().filter(item -> !BatchScanStatusEnum.scanning.name().equals(item.getStatus())).toList();
        if (CollectionUtil.isEmpty(list)) {
            throw new AssetsDiscoverException("not-scan");
        }
        return list;
    }

    private AssetsScanParam failResultListConvertScanParam(List<ScanResultFailInfo> list, String id) throws Exception {
        AssetsScanParam scanParam = new AssetsScanParam();
        List<String> ips = list.stream().map(ScanResultFailInfo::getIpAddress).toList();

        scanParam.setTaskId(id);
        scanParam.setIps(String.join("\n", ips));
        // 获取id对应的实例的扫描规则信息
        AssetsDiscoverServiceImpl discoverService = (AssetsDiscoverServiceImpl) this.cmdbServiceManage.getModelService(AssetsDiscoverServiceImpl.ID);
        AssetsDiscoverInfo discoverInfo = discoverService.doSelectById(id);

        // 解析DATA获取扫描规则信息、引擎、等等信息
        List<AssetsDiscoverRuleParam> mwScanRuleTypes = discoverInfo.getScanRules();
        if (CollectionUtil.isNotEmpty(mwScanRuleTypes)) {
            List<RuleParam> ruleParams = AssetsDiscoverRuleParam.discoverRuleConvertRuleParam(mwScanRuleTypes, discoverInfo);
            scanParam.setRuleParams(ruleParams);
        }
        AssertBatchScanProperty batchScanProperty = discoverService.discoverInfoToAssetsScanParam(discoverInfo);

        if (StringUtils.hasText(batchScanProperty.getMonitorServerId())) {
            scanParam.setMw_monitorServerId(Integer.parseInt(batchScanProperty.getMonitorServerId()));
        }

        return scanParam;
    }

    public List<AssetsDiscoverInfo> getAssetDiscoverInfoListByIds(List<String> ids) throws Exception {
        AssetsDiscoverSearchParam searchParam = new AssetsDiscoverSearchParam();
        Map<String, SubCondition> condition = new HashMap<>();

        condition.put(getFieldName(AssetsDiscoverInfo::getId), new SubCondition(CriteriaOpsType.in.name(), ids));

        searchParam.setCondition(condition);
        //查询数据库资产发现信息
        List<AssetsDiscoverInfo> ret = doSelectList(searchParam);

        //查询正在执行的资产发现任务,并设置状态
        Map<String, AssetsDiscoverInfo> scanningMap = runManage.getScaningAssetsDiscoverInfoMap();
        for (AssetsDiscoverInfo assetsDiscoverInfo : ret) {
            AssetsDiscoverInfo scanning = scanningMap.get(assetsDiscoverInfo.getId());
            if (null != scanning) {
                BatchScanStatusEnum status = BatchScanStatusEnum.valueOf(scanning.getStatus());
                switch (status) {
                    case fail, success -> runManage.clearDiscovery(scanning);
                    case scanning -> {
                        assetsDiscoverInfo.setProgress(scanning.getProgress());
                        assetsDiscoverInfo.setStatus(BatchScanStatusEnum.scanning.name());
                    }
                    default -> log.info("unknown status : {}", status);
                }
            }
        }
        return ret;
    }

    private List<AssetsScanParam> instanceToScanParam(List<AssetsDiscoverInfo> discoverInfos) {
        List<AssetsScanParam> scanParamList = Lists.newArrayList();

        for (AssetsDiscoverInfo discoverInfo : discoverInfos) {

            AssetsScanParam assetsScanParam = new AssetsScanParam();

            AssertBatchScanProperty batchScanProperty = discoverInfoToAssetsScanParam(discoverInfo);
            assetsScanParam.setTaskId(discoverInfo.getId());
            assetsScanParam.setMw_proxyType(batchScanProperty.getProxyType());
            assetsScanParam.setMw_pollingEngine(batchScanProperty.getPollingEngine());
            if (StringUtils.hasText(batchScanProperty.getMonitorServerId())) {
                assetsScanParam.setMw_monitorServerId(Integer.parseInt(batchScanProperty.getMonitorServerId()));
            }

            List<IPRangeParam> mwIpRanges = batchScanProperty.getIpRange();
            if (CollectionUtil.isNotEmpty(mwIpRanges)) {
                assetsScanParam.setIpranges(mwIpRanges);
            }

            List<SubnetParam> mwIpSubnets = batchScanProperty.getIpSubnet();
            if (CollectionUtil.isNotEmpty(mwIpSubnets)) {
                assetsScanParam.setSubnets(mwIpSubnets);
            }
            if (CollectionUtil.isNotEmpty(batchScanProperty.getScanRuleTypes())) {
                assetsScanParam.setRuleParams(batchScanProperty.getScanRuleTypes());
            }
            if (StrUtil.isNotEmpty(batchScanProperty.getIps())) {
                String ips = batchScanProperty.getIps().replaceAll(",", "\n");
                assetsScanParam.setIps(ips);
            }

            scanParamList.add(assetsScanParam);
        }

        return scanParamList;
    }

    public AssertBatchScanProperty discoverInfoToAssetsScanParam(AssetsDiscoverInfo discoverInfo) {
        AssertBatchScanProperty batchScanProperty = new AssertBatchScanProperty();
        batchScanProperty.setTaskType(discoverInfo.getTaskType());
        batchScanProperty.setCheckNowFlag(discoverInfo.getExecutorNow());
        batchScanProperty.setExecutorNow(true);
        batchScanProperty.setIpRange(discoverInfo.getIpRange());
        batchScanProperty.setIpSubnet(discoverInfo.getIpSubnet());
        batchScanProperty.setProxyType(discoverInfo.getProxyType());
        batchScanProperty.setPollingEngine(discoverInfo.getEngineId());
        List<AssetsDiscoverRuleParam> scanRules = discoverInfo.getScanRules();
        if (CollectionUtil.isNotEmpty(scanRules)) {
            List<RuleParam> ruleParams = AssetsDiscoverRuleParam.discoverRuleConvertRuleParam(scanRules, discoverInfo);
            batchScanProperty.setScanRuleTypes(ruleParams);
        }
        if (ObjUtil.isNotEmpty(discoverInfo.getIpv6checked())) {
            batchScanProperty.setIpv6checked(discoverInfo.getIpv6checked());
        }
        batchScanProperty.setIps(discoverInfo.getIps());
        return batchScanProperty;
    }

    public List<AssetsDiscoverInfo> getRuleDetail(AssetsDiscoverIdsParam param) throws Exception {
        return getAssetDiscoverInfoListByIds(param.getIds());
    }

    //一天的分钟数
    private static final int DAY_LEN = 1440;

    public static String scanRuleTime(Long scanStartTime, Long scanEndTime) {
        return scanRuleTime(new Date(scanStartTime), new Date(scanEndTime));
    }

    public static String scanRuleTime(Date scanStartTime, Date scanEndTime) {
        if (null == scanEndTime) {
            return Constants.UNKNOWN;
        }
        long period = scanEndTime.getTime() - scanStartTime.getTime();
        int length = (int) (period / (1000 * 60));

        if (length <= 0) {
            length = (int) (period / 1000);
            return (length + "秒");
        }

        if (length >= DAY_LEN) {
            int days = length / DAY_LEN;
            int minutes = length % DAY_LEN;
            return (days + "天" + minutes + "分钟");
        }
        return (length + "分钟");
    }

    public List<String> getProxyType() {
        List<MwTPServerTable> allMwTpServer = mwTPServerService.getAllMwTpServer(ServerTypeEnum.Zabbix.getCode(), false);
        boolean hasZabbix7 = CMDBCommonUtil.hasZabbix7Server(allMwTpServer);
        List<String> ret = new ArrayList<>();
        if (hasZabbix7) {
            ret.add(ProxyTypeEnum.pollingEngine.name());
            ret.add(ProxyTypeEnum.pollingGroup.name());
        } else {
            ret.add(ProxyTypeEnum.pollingEngine.name());
        }
        return ret;
    }

    public <T> List<T> getCountAggregationQuery(String groupField, String maxField, Integer count,
                                                BaseMapper baseMapper, String collectionName, Class<T> entityClass) throws Exception {
//       return getMaxFieldValues(baseMapper,entityClass,groupField,null,maxField,null);
        // Group阶段：按game_record_id分组，取record_id的最大值，并获取对应的文档
        GroupOperation groupStage = Aggregation.group(groupField)
                .max(maxField).as(maxField)
                .first("$$ROOT").as("data");

        // Project阶段：选择所需字段
        ProjectionOperation projectStage = Aggregation.project()
                .and("_id").as(groupField)
                .and(maxField).as(maxField)
                .and("data.successList").as("successList")
                .and("data.failList").as("failList");

        // 组合聚合管道
        Aggregation aggregation = Aggregation.newAggregation(
                groupStage,
                projectStage
        );
        // 执行聚合查询
        AggregationResults<T> results = baseMapper.aggregate(aggregation, collectionName, entityClass);
        return results.getMappedResults();
    }

    public void deleteTimePlanRelationInfo(AssetsDiscoverInfo param) throws Exception {
        try {
            MwTimePlanCommonImpl mwTimePlanCommon = SpringUtils.getBean(MwTimePlanCommonImpl.class);
            mwTimePlanCommon.deleteTimePlanRelationInfo(param.getId());
        } catch (Exception e) {
            log.error("deleteTimePlanRelationInfo to fail::", e);
        }
    }

    public void createTimeTaskScanPlan(AssetsDiscoverInfo param) throws Exception {
        MwTimePlanCommonImpl mwTimePlanCommon = SpringUtils.getBean(MwTimePlanCommonImpl.class);
        mwTimePlanCommon.deleteTimePlanRelationInfo(param.getId());
        String relationalPlan = param.getTimePlanId();
        if (org.apache.commons.lang3.StringUtils.isEmpty(relationalPlan)) {
            return;
        }
        //调用关联计划API
        MwTimePlanparam timePlanparam = new MwTimePlanparam();
        timePlanparam.setTimePlanId(relationalPlan);
        timePlanparam.setTypeId(param.getId());
        timePlanparam.setModuleName(MwTimePlanEnum.ASSETS_SCAN_MANAGE.getModuleName());
        timePlanparam.setJobName(MwTimePlanEnum.ASSETS_SCAN_MANAGE.getModuleName() + param.getRuleName() + System.currentTimeMillis());
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put(TASK_RULE_ID_KEY, param.getId());
        timePlanparam.setJobParams(JSON.toJSONString(paramMap));
        timePlanparam.setProcessorInfo(MwTimePlanEnum.ASSETS_SCAN_MANAGE.getClassName());
        mwTimePlanCommon.generatePowerJob(timePlanparam);
    }


}
